package com.zhb.cloud.hystrix.command;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.zhb.cloud.model.User;
import com.zhb.cloud.service.UserService;

/**
 * @ClassName: HystrixCircuitBreaker
 * @author: zhb
 * @date: 2017年8月8日 下午2:53:52
 * @Description: 熔断实现的方式一 前端发起请求通过url地址到达网关,通过自定义的HystrixCommand传入请求地址调用服务提供方
 *               前提该方式适合用于restful风格的服务调用--不适合rpc
 * 
 */
public class CustomerHystrixCommand extends HystrixCommand<Map<String, Object>> {
	Logger logger = LoggerFactory.getLogger(CustomerHystrixCommand.class);
	private static final int DEFAULT_THREADPOOL_CORE_SIZE = 10;
	public final Map<String, Object> map;

	/**
	 * 断路器配置未来可优化为动态配置，策略不写死在代码中
	 */
	public CustomerHystrixCommand(Map<String, Object> map) {
		// 用Dubbo服务提供者接口名来定义断路器分组key
		super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("consumer"))
				// 用Dubbo服务提供者接口的方法名+方法入参个数定义相同依赖的key
				.andCommandKey(HystrixCommandKey.Factory.asKey("test"))
				// 重写断路器基本策略属性
				.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
						// 断路器是否开启，默认：true
						.withCircuitBreakerEnabled(true)
						// 统计时间滚动窗口，以毫秒为单位，默认：10秒
						.withMetricsRollingStatisticalWindowInMilliseconds(10000)
						// 断路器在整个统计时间内是否开启的阀值，也就是10秒钟内至少请求10次，断路器才发挥起作用
						.withCircuitBreakerRequestVolumeThreshold(10)
						// 断路器默认工作时间，默认:5秒，断路器中断请求5秒后会进入半打开状态，放部分流量过去重试
						.withCircuitBreakerSleepWindowInMilliseconds(5000)
						// 当出错率超过30%后断路器启动，默认:50%
						.withCircuitBreakerErrorThresholdPercentage(30)
						// 是否开启Hystrix超时机制，这里禁用Hystrix的超时，使用dubbo的超时
						.withExecutionTimeoutEnabled(true).withExecutionTimeoutInMilliseconds(10000))
				// 线程池配置，可考虑获取Dubbo提供者的线程数来配置断路器的线程数，若使用Hystrix的线程数则应大于Dubbo服务提供者的线程数，保证管道匹配
				.andThreadPoolPropertiesDefaults(
						HystrixThreadPoolProperties.Setter().withCoreSize(DEFAULT_THREADPOOL_CORE_SIZE)));
		this.map = map;
	}

	/**
	 * 根据需要重写失败回退逻辑（降级逻辑）
	 * 
	 * @return
	 */
	@Override
	protected Map<String, Object> getFallback() {
		Map<String, Object> map = new HashMap<>();
		map.put("code", "100");
		map.put("data", "太火爆了");
		map.put("message", "太火爆了");
		return map;
	}

	@Override
	protected Map<String, Object> run() throws Exception {
		UserService userService = (UserService) map.get("service");
		User user = userService.findByUserName(map.get("userName").toString());
		Map<String, Object> map = new HashMap<>();
		map.put("code", "200");
		map.put("data", user);
		map.put("message", "查询成功");
		return map;
	}
}
